#include "unpack_process.hh"
using namespace std;

unpack_process::unpack_process(string input_file, int asic_num, string root_filename, bool is_write_txt, bool is_base_data, bool is_set_same_rms, double LSB, int thresh_limit, string save_path, string file_write, bool is_extra_trigger) : ch(asic_num), amp(asic_num)
{
  this->input_file = input_file;
  this->asic_num = asic_num;
  this->LSB = LSB;
  this->thresh_limit = thresh_limit;
  this->save_path = save_path;
  this->file_write = file_write;
  this->is_extra_trigger = is_extra_trigger;
  this->is_set_same_rms = is_set_same_rms;
  if (init_file())
    {
      if (is_base_data)
        {
          base_data();
        }
      else
        {
          init_root(root_filename);
          write_root();
          complete_adding();
          if (is_write_txt)
            {
              string txt_filename = root_filename + ".txt";
              ofstream file(txt_filename, ios::out);
              write_txt(txt_filename);
              file.close();
            }
        }
    }
  else
    {
      cout << cRED << "error read data" << cRESET << endl;
      return;
    }
}

unpack_process::~unpack_process()
{
  if (adas_hit_file != nullptr && adas_hit_file->IsOpen())
    {
      adas_hit_file->Close();
      delete adas_hit_tree;
      delete adas_hit_file;
    }
}

// bool unpack_process::init_file1()
// {
//     ifstream data_file;
//     unsigned char *data_buffer;

//     long data_num_bytes;
//     data_file.open(input_file, ifstream::binary);

//     if (!data_file.is_open())
//     {
//         cout << cRED << "Error: cannot open file " << input_file << cRESET << endl;
//         return false;
//     }
//     else
//     {
//         data_file.seekg(0, data_file.end);
//         data_num_bytes = data_file.tellg();
//         data_file.seekg(0, data_file.beg);
//         data_buffer = new unsigned char[data_num_bytes];
//         data_file.read((char *)data_buffer, data_num_bytes);
//         int i = 0;
//         int trig_cnt = 0;
//         int trig_event = 0;
//         int trig_now = 0;
//         int cnt = 0;
//         bool usb_desperate_flag = false;
//         uint32_t value = 0;
//         vector<uint32_t> temp_idx;
//         vector<uint32_t> temp_amp;
//         vector<uint32_t> temp_chl;
//         int numberidx = 0;
//         int idxcnt = 0;
//         while (i < data_num_bytes)
//         {
//             if (!usb_desperate_flag && (((data_buffer[i] << 8) | (data_buffer[i + 1])) != header))
//             {
//                 i++;
//                 continue;
//             }
//             else
//             {
//                 usb_desperate_flag = true;
//                 if (trig_cnt == asic_num)
//                 {
//                     trig_cnt = 0;
//                     trig.push_back(trig_now);
//                     adas_idx.push_back(temp_idx);
//                     adas_chl.push_back(temp_chl);
//                     adas_amp.push_back(temp_amp);
//                     temp_amp.clear();
//                     temp_chl.clear();
//                     temp_idx.clear();
//                 }

//                 value = (data_buffer[i] << 24) | (data_buffer[i + 1] << 16) | (data_buffer[i + 2] << 8) | data_buffer[i + 3];
//                 bitset<32> bits1(value);
//                 bitset<16> hig16(bits1.to_string().substr(0, 16));
//                 bitset<14> low14(bits1.to_string().substr(32 - 14, 14));
//                 int msb = hig16.to_ulong();
//                 int lsb = low14.to_ulong();
//                 if (msb == header)
//                 {
//                     int idx_num = 0;
//                     i += 4;
//                     value = (data_buffer[i] << 24) | (data_buffer[i + 1] << 16) | (data_buffer[i + 2] << 8) | data_buffer[i + 3];
//                     trig_event = value;
//                     if (trig_cnt == 0)
//                     {
//                         trig_now = trig_event;
//                         trig_cnt++;
//                     }
//                     else
//                     {
//                         if (trig_now == trig_event)
//                         {
//                             trig_cnt++;
//                         }
//                         else
//                         {
//                             trig_cnt = 1;
//                             trig_now = trig_event;
//                             temp_amp.clear();
//                             temp_chl.clear();
//                             temp_idx.clear();
//                         }
//                     }
//                     i += 4;
//                     value = (data_buffer[i] << 24) | (data_buffer[i + 1] << 16) | (data_buffer[i + 2] << 8) | data_buffer[i + 3];
//                     if (value == lsb / 4 + 2)
//                     {
//                         i += 4;
//                         value = (data_buffer[i] << 24) | (data_buffer[i + 1] << 16) | (data_buffer[i + 2] << 8) | data_buffer[i + 3];
//                         bitset<32> bits2(value);
//                         bitset<8> hig8(bits2.to_string().substr(32 - 16, 8));
//                         bitset<8> low8(bits2.to_string().substr(32 - 8, 8));
//                         int asic_idx = hig8.to_ulong();
//                         int idx_cnt = low8.to_ulong();
//                         i += 4;
//                         if ((idx_cnt + 5) == (lsb / 4 + 2))
//                         {
//                             for (int j = 0; j < idx_cnt; j++)
//                             {
//                                 value = (data_buffer[i] << 24) | (data_buffer[i + 1] << 16) | (data_buffer[i + 2] << 8) | data_buffer[i + 3];
//                                 bitset<32> bits3(value);
//                                 bitset<8> ch8(bits3.to_string().substr(0, 8));
//                                 bitset<24> amp24(bits3.to_string().substr(32 - 24, 24));
//                                 int asic_chl = ch8.to_ulong();
//                                 int asic_amp = amp24.to_ulong();
//                                 if (asic_chl >= 1 && asic_chl <= 128)
//                                 {
//                                     if ((asic_amp - 16384) < 0 && abs(asic_amp - 16384) * LSB > 3.9 && is_extra_trigger)
//                                     {
//                                         temp_idx.push_back(asic_idx);
//                                         temp_chl.push_back(asic_chl);
//                                         temp_amp.push_back(asic_amp);
//                                     }
//                                     else if (!is_extra_trigger)
//                                     {
//                                         temp_idx.push_back(asic_idx);
//                                         temp_chl.push_back(asic_chl);
//                                         temp_amp.push_back(asic_amp);
//                                     }
//                                 }
//                                 i += 4;
//                             }
//                         }
//                         else
//                         {
//                             continue;
//                         }
//                     }
//                     else
//                     {
//                         continue;
//                     }
//                 }
//                 else
//                 {
//                     i += 4;
//                 }
//             }
//         }

//         if (trig.empty())
//         {
//             cout << cRED << "error read data" << cRESET << endl;
//             return false;
//         }
//         cout << cBLUE << "fec data spilt suceess" << cRESET << endl;
//         cout << endl;
//         delete[] data_buffer;
//         data_file.close();
//         return true;

//         // ofstream file("data.txt", ios::out);
//         // for (int i = 0; i < 2; i++)
//         // {
//         //     file << trig[i] << " ";
//         //     for (int j = 0; j < adas_chl[i].size(); j++)
//         //     {
//         //         file << adas_idx[i][j] << " " << adas_chl[i][j] << " " << adas_amp[i][j] << " ";
//         //     }
//         //     file << endl;
//         // }
//         // file.close();
//     }
// }

bool unpack_process::init_file()
{
  ifstream data_file(input_file, ifstream::binary);
  if (!data_file.is_open())
    {
      cout << cRED << "Error: cannot open file " << input_file << cRESET << endl;
      return false;
    }
  // 读取数据到缓冲区
  const size_t buffer_size = 1024 * 1024;                                  // 1 MB buffer
  unique_ptr<unsigned char[]> data_buffer(new unsigned char[buffer_size]); // 1 MB buffer

  int k = 0;
  int trig_cnt = 0;
  int trig_event = 0;
  int trig_now = 0;
  bool usb_desperate_flag = false;
  uint32_t value = 0;
  vector<uint32_t> temp_idx;
  vector<uint32_t> temp_amp;
  vector<uint32_t> temp_chl;

  size_t remaining_bytes = 0;

  while (data_file)
    {

      // 读取数据到缓冲区，从remaining_bytes字节开始
      data_file.read(reinterpret_cast<char *>(data_buffer.get() + remaining_bytes), buffer_size);
      size_t bytes_read = data_file.gcount();
      if (bytes_read == 0)
        break; // 如果没有读取到字节，退出循环

      bytes_read += remaining_bytes; // 总的字节数包括复制的remaining_bytes
      size_t i = 0;

      while (i < bytes_read)
        {
          if (!usb_desperate_flag && (((data_buffer[i] << 8) | (data_buffer[i + 1])) != header))
            {
              i++;
              continue;
            }
          else
            {
              usb_desperate_flag = true;
              if (trig_cnt == asic_num)
                {
                  trig_cnt = 0;
                  trig.push_back(trig_now);
                  adas_idx.push_back(temp_idx);
                  adas_chl.push_back(temp_chl);
                  adas_amp.push_back(temp_amp);
                  temp_amp.clear();
                  temp_chl.clear();
                  temp_idx.clear();
                }

              if (i + 3 >= bytes_read)
                break; // 确保不会超出缓冲区
              value = (data_buffer[i] << 24) | (data_buffer[i + 1] << 16) | (data_buffer[i + 2] << 8) | data_buffer[i + 3];
              bitset<32> bits1(value);
              bitset<16> hig16(bits1.to_string().substr(0, 16));
              bitset<14> low14(bits1.to_string().substr(32 - 14, 14));
              int msb = hig16.to_ulong();
              int lsb = low14.to_ulong();
              if (msb == header)
                {
                  // 检查后面第 (lsb / 4 + 1) 个 32 位值是否为 0x4038666，并且不会溢出
                  // 这里的 0x4038666 是adas的包尾，用于判断是否是一个完整的数据块
                  // 实际情况下需要根据你的包尾修改
                  size_t check_pos = i + lsb + 4;
                  if (check_pos + 3 >= bytes_read)
                    {
                      break;
                    }
                  value = (data_buffer[check_pos] << 24) | (data_buffer[check_pos + 1] << 16) | (data_buffer[check_pos + 2] << 8) | data_buffer[check_pos + 3];
                  if (value != 1077438054) // 在这里修改包尾值 1077438054对应0x4038666
                    {
                      break;
                    }
                  // 后续处理 根据数据格式修改
                  int idx_num = 0;
                  i += 4;
                  value = (data_buffer[i] << 24) | (data_buffer[i + 1] << 16) | (data_buffer[i + 2] << 8) | data_buffer[i + 3];
                  trig_event = value;
                  if (trig_cnt == 0)
                    {
                      trig_now = trig_event;
                      trig_cnt++;
                    }
                  else
                    {
                      if (trig_now == trig_event)
                        {
                          trig_cnt++;
                        }
                      else
                        {
                          trig_cnt = 1;
                          trig_now = trig_event;
                          temp_amp.clear();
                          temp_chl.clear();
                          temp_idx.clear();
                        }
                    }
                  i += 4;
                  value = (data_buffer[i] << 24) | (data_buffer[i + 1] << 16) | (data_buffer[i + 2] << 8) | data_buffer[i + 3];
                  if (value == lsb / 4 + 2)
                    {
                      i += 4;
                      value = (data_buffer[i] << 24) | (data_buffer[i + 1] << 16) | (data_buffer[i + 2] << 8) | data_buffer[i + 3];
                      bitset<32> bits2(value);
                      bitset<8> hig8(bits2.to_string().substr(32 - 16, 8));
                      bitset<8> low8(bits2.to_string().substr(32 - 8, 8));
                      int asic_idx = hig8.to_ulong();
                      int idx_cnt = low8.to_ulong();
                      i += 4;

                      if ((idx_cnt + 5) == (lsb / 4 + 2))
                        {
                          for (int j = 0; j < idx_cnt; j++)
                            {
                              value = (data_buffer[i] << 24) | (data_buffer[i + 1] << 16) | (data_buffer[i + 2] << 8) | data_buffer[i + 3];
                              bitset<32> bits3(value);
                              bitset<8> ch8(bits3.to_string().substr(0, 8));
                              bitset<24> amp24(bits3.to_string().substr(32 - 24, 24));
                              int asic_chl = ch8.to_ulong();
                              int asic_amp = amp24.to_ulong();
                              if (asic_chl >= 1 && asic_chl <= 128)
                                {
                                  if ((asic_amp - 16384) < 0 && abs(asic_amp - 16384) * LSB > 3.9 && is_extra_trigger) // [todo] soft-trigger
                                    {
                                      temp_idx.push_back(asic_idx);
                                      temp_chl.push_back(asic_chl);
                                      temp_amp.push_back(asic_amp);
                                    }
                                  else if (!is_extra_trigger)
                                    {
                                      if (asic_idx > 16)
                                        {
                                          k++;
                                        }
                                      temp_idx.push_back(asic_idx);
                                      temp_chl.push_back(asic_chl);
                                      temp_amp.push_back(asic_amp);
                                    }
                                }
                              i += 4;
                            }
                        }
                      else
                        {
                          continue;
                        }
                    }
                  else
                    {
                      continue;
                    }
                }
              else
                {
                  i += 4;
                }
            }
        }

      // 计算剩余的字节数
      remaining_bytes = bytes_read - i;
      if (remaining_bytes > 0)
        {
          memcpy(data_buffer.get(), data_buffer.get() + i, remaining_bytes);
        }
    }

  if (trig.empty())
    {
      cout << cRED << "error read data" << cRESET << endl;
      return false;
    }
  cout << cBLUE << "fec data spilt suceess" << cRESET << endl;
  cout << k << endl;
  cout << endl;
  data_file.close();
  return true;
}

void unpack_process::base_data()
{
  vector<vector<vector<uint32_t>>> base(asic_num);
  vector<vector<double>> means(asic_num);
  vector<vector<double>> means128(asic_num);
  vector<vector<double>> rms(asic_num);
  vector<vector<double>> rms_bin(asic_num);
  vector<vector<double>> rms128(asic_num);
  vector<vector<double>> threshold(asic_num);

  for (int i = 0; i < adas_amp.size(); ++i)
    {
      for (int j = 0; j < adas_amp[i].size(); j += 128)
        {
          vector<uint32_t> group;
          double k = 0;
          k = j / 128;
          group.insert(group.end(), adas_amp[i].begin() + j, adas_amp[i].begin() + j + 128);
          amp[k].push_back(group);
        }
    }

  for (int i = 0; i < asic_num; i++)
    {
      clac_base_rms(amp[i], base[i], means[i], rms[i], threshold[i], rms_bin[i], rms128[i], means128[i]);
    }

  vector<double> th;
  for (int i = 0; i < threshold.size(); i++)
    {
      for (int j = 0; j < threshold[i].size(); j++)
        {
          th.push_back(threshold[i][j]);
        }
    }
  if (is_set_same_rms)
    {
      threshold_to_gbt_same(th);
    }
  else
    {
      threshold_to_gbt(th);
    }
  draw(means, rms);
  write_base_txt(means128, rms128, threshold);

  cout << cBLUE << "base data suceess" << cRESET << endl;
  cout << endl;
}

void unpack_process::write_root()
{

  if (trig.size() != adas_idx.size())
    {
      cout << "error read data" << endl;
    }

  for (int i = 0; i < trig.size(); i++)
    {
      nhits = adas_chl[i].size();
      triggerid = trig[i];
      for (int j = 0; j < nhits; j++)
        {
          adas_hit_idx[j] = adas_idx[i][j];
          adas_hit_chl[j] = adas_chl[i][j];
          adas_hit_amp[j] = adas_amp[i][j];
        }
      if (adas_hit_tree != nullptr)
        {
          adas_hit_tree->Fill();
        }
      else
        {
          cout << "adas_hit_tree is not initialized!" << std::endl;
        }
    }

  cout << cBLUE << "write root suceess" << cRESET << endl;
  cout << endl;
}

bool unpack_process::init_root(string root_filename)
{
  string filename = root_filename + ".root";
  adas_hit_file = new TFile(filename.c_str(), "recreate");
  adas_hit_tree = new TTree("adas_initial_data", "ADAS Hit");

  adas_hit_tree->Branch("nhits", &nhits, "nhits/I");
  adas_hit_tree->Branch("triggerid", &triggerid, "triggerid/I");
  adas_hit_tree->Branch("adas_hit_idx", adas_hit_idx, "adas_hit_idx[nhits]/I");
  adas_hit_tree->Branch("adas_hit_chl", adas_hit_chl, "adas_hit_chl[nhits]/I");
  adas_hit_tree->Branch("adas_hit_amp", adas_hit_amp, "adas_hit_amp[nhits]/I");

  cout << cCYAN << "TTree in TFile " << cMAGENTA << filename << cCYAN << " init done" << cRESET << endl;
  cout << cGREEN << filename << cRESET << endl;
  cout << endl;

  return true;
}

void unpack_process::complete_adding()
{
  if (adas_hit_tree != nullptr)
    {
      adas_hit_file->cd();
      adas_hit_tree->Write();
      adas_hit_file->Flush();
      adas_hit_file->Close();
    }
  else
    {
      cout << "adas_hit_tree is not initialized!" << std::endl;
    }
}

void unpack_process::write_txt(string filename)
{
  ofstream file(filename, ios::out);
  for (int i = 0; i < adas_chl.size(); i++)
    {
      file << trig[i] << " ";
      for (int j = 0; j < adas_chl[i].size(); j++)
        {
          file << adas_idx[i][j] << " " << adas_chl[i][j] << " " << adas_amp[i][j] << " ";
        }
      file << endl;
    }
  file.close();
}

void unpack_process::clac_base_rms(vector<vector<uint32_t>> data, vector<vector<uint32_t>> &base, vector<double> &means, vector<double> &rms, vector<double> &threshold, vector<double> &rms_bin, vector<double> &rms128, vector<double> &means128)
{

  for (int i = 0; i < data.size(); i++)
    {
      vector<uint32_t> temp_base;
      for (int j = 0; j < 128; j++)
        {
          temp_base.push_back(data[i][j]);
        }
      base.push_back(temp_base);
    }

  int rows = base.size();
  int cols = base[0].size();

  for (int i = 0; i < cols; i++)
    {
      double sum = 0;
      for (int j = 0; j < rows; j++)
        {
          sum += base[j][i];
        }
      means.push_back(sum / rows);
    }

  vector<double> temp;

  for (int i = 0; i < cols; i++)
    {
      double sum = 0;
      for (int j = 0; j < rows; j++)
        {
          sum += pow(base[j][i] - means[i], 2);
        }
      temp.push_back(sqrt(sum / rows));
    }

  for (int i = 0; i < cols; i++)
    {
      rms.push_back(temp[i] * LSB);
    }

  means128.resize(128);
  rms128.resize(128);

  for (int i = 0; i < cols; i++)
    {
      means128[i] = means[i];
      rms128[i] = rms[i];
    }

  for (int i = 0; i < means.size(); i++)
    {
      int th = 0;
      th = thresh_limit * temp[i];
      threshold.push_back(th);
    }

  for (int i = 0; i < cols; i++)
    {
      rms_bin.push_back(temp[i]);
    }

  // 需要注意的是adas1128输出数据后64个通道是从128-65，并不是65-128，所以在画图的时候需要将64个通道的数据反过来；但是填入阈值的时候是不需要翻转的
  // mean和rms为了画图，写入txt的为mean128，rms128，threshold
  int n = 0;
  for (int i = 0; i < means.size(); i++)
    {
      if (i > 63 && n <= 32)
        {
          int t = 0;
          double r = 0;
          t = means[i];
          means[i] = means[191 - i];
          means[191 - i] = t;
          r = rms[i];
          rms[i] = rms[191 - i];
          rms[191 - i] = r;
          n++;
        }
    }
}

void unpack_process::threshold_to_usb(vector<double> threshold)
{
  vector<double> th;

  th = threshold;

  for (int i = 128; i < th.size() + (asic_num * 3); i += 128 + 3)
    {

      th.insert(th.begin() + i, 3, 0);
    }

  ostringstream datamsb;
  ostringstream datalsb;

  long DataMSB = 0x0208;
  long DataLSB = 0x0209;
  string datamsb_str;
  string datalsb_str;
  string wr_str;

  string bin_str;
  string bin_res;
  string bin_addr;
  string m_str;
  string l_str;

  string filename = save_path + "th.txt";
  ofstream output_file(filename, ios::out | ios::trunc);

  for (int i = 0; i < asic_num; i++)
    {
      for (int j = 0; j < 131; j++)
        {

          bitset<24> bits((int)(th[j + i * 131]));
          bitset<8> bits3(j);
          bin_str = bits.to_string();
          bin_addr = bits3.to_string();
          bin_res = bin_addr + bin_str;

          m_str = bin_res.substr(0, 16);
          l_str = bin_res.substr(16, 16);

          bitset<16> bits1(m_str);
          int msb = bits1.to_ulong();

          bitset<16> bits2(l_str);
          int lsb = bits2.to_ulong();

          datamsb << "0x" << setfill('0') << setw(4) << hex << DataMSB << setw(4) << hex << msb;
          datamsb_str = datamsb.str();

          datalsb << "0x" << setfill('0') << setw(4) << hex << DataLSB << setw(4) << hex << lsb;
          datalsb_str = datalsb.str();

          wr_str = "0x020" + to_string(i + 4) + "0001";
          output_file << datamsb_str << endl;
          output_file << datalsb_str << endl;
          output_file << wr_str << endl;
          datamsb.str("");
          datalsb.str("");
        }
    }
  output_file.close();

  cout << cBLUE << "sucess output " << filename << endl;
  cout << endl;
}

void unpack_process::threshold_to_usb_new(vector<double> threshold)
{
  vector<double> th;

  th = threshold;

  for (int i = 128; i < th.size() + (asic_num * 3); i += 128 + 3)
    {

      th.insert(th.begin() + i, 3, 0);
    }

  ostringstream datamsb;
  ostringstream datalsb;

  long DataMSB = 0x0200;
  long DataLSB = 0x0201;
  string datamsb_str;
  string datalsb_str;
  string wr_str;

  string bin_str;
  string bin_res;
  string bin_addr;
  string m_str;
  string l_str;

  string filename = file_write;
  ofstream output_file(filename, ios::out | ios::trunc);

  for (int i = 0; i < asic_num; i++)
    {
      for (int j = 0; j < 131; j++)
        {

          bitset<24> bits((int)(th[j + i * 131]));
          bitset<8> bits3(j + 1);
          bin_str = bits.to_string();
          bin_addr = bits3.to_string();
          bin_res = bin_addr + bin_str;

          m_str = bin_res.substr(0, 16);
          l_str = bin_res.substr(16, 16);

          bitset<16> bits1(m_str);
          int msb = bits1.to_ulong();

          bitset<16> bits2(l_str);
          int lsb = bits2.to_ulong();

          datamsb << "0x" << setfill('0') << setw(4) << hex << DataMSB << setw(4) << hex << msb;
          datamsb_str = datamsb.str();

          datalsb << "0x" << setfill('0') << setw(4) << hex << DataLSB << setw(4) << hex << lsb;
          datalsb_str = datalsb.str();

          int wren = i + 10;
          stringstream ss;
          ss << hex << wren;
          string idx = ss.str();

          wr_str = "0x020" + idx + "0001";
          output_file << datamsb_str << endl;
          output_file << datalsb_str << endl;
          output_file << wr_str << endl;
          datamsb.str("");
          datalsb.str("");
        }
    }
  output_file.close();

  cout << cYELLOW << "threshold txt sucess output " << filename << endl;
  cout << endl;
}

void unpack_process::threshold_to_gbt(vector<double> threshold)
{
  vector<double> th;

  th = threshold;

  for (int i = 128; i < th.size() + (asic_num * 3); i += 128 + 3)
    {

      th.insert(th.begin() + i, 3, 0);
    }

  long DataMSB = 0x0101;
  long DataLSB = 0x0102;
  string enable = "0x01020001";

  string wait = "&1";

  ostringstream datamsb;
  ostringstream datalsb;

  string bin_str;
  string bin_res;
  string bin_addr;
  string m_str;
  string l_str;
  string datamsb_str;
  string datalsb_str;

  string filename = file_write;
  ofstream output_file(filename, ios::out | ios::trunc);

  for (int i = 0; i < asic_num; i++)
    {

      for (int j = 0; j < 131; j++)
        {

          for (int k = 0; k < 2; k++)
            {

              string wr_msb_en = "0x0101400" + to_string(k);

              output_file << wr_msb_en << endl;
              output_file << enable << endl;

              bitset<24> bits((int)(th[j + i * 131]));
              bitset<8> bits3(j + 1);
              bin_str = bits.to_string();
              bin_addr = bits3.to_string();
              bin_res = bin_addr + bin_str;

              m_str = bin_res.substr(0, 16);
              l_str = bin_res.substr(16, 16);

              bitset<16> bits1(m_str);
              int msb = bits1.to_ulong();

              bitset<16> bits2(l_str);
              int lsb = bits2.to_ulong();

              datamsb << "0x" << setfill('0') << setw(4) << hex << DataMSB << setw(4) << hex << msb;
              datamsb_str = datamsb.str();

              datalsb << "0x" << setfill('0') << setw(4) << hex << DataMSB << setw(4) << hex << lsb;
              datalsb_str = datalsb.str();

              if (k == 0)
                {
                  output_file << datamsb_str << endl;
                }
              else
                {
                  output_file << datalsb_str << endl;
                }

              output_file << enable << endl;
              output_file << wait << endl;
              datamsb.str("");
              datalsb.str("");
            }
          output_file << "0x01014012" << endl;
          output_file << enable << endl;
          output_file << "0x01010000" << endl;
          output_file << enable << endl;
          output_file << wait << endl;

          // WREN EN
          if (i <= 16)
            {
              output_file << "0x01015000" << endl;
              output_file << enable << endl;

              int en = 1;
              int wren = 1 << i;
              wren = wren & 0xffff;
              stringstream ss;
              ss << setw(4) << setfill('0') << hex << wren;
              string idx = ss.str();
              string ram_wren = "0x0101" + idx;
              output_file << ram_wren << endl;

              output_file << enable << endl;
            }
          else
            {
              int en = 1;
              int wren = 1 << (i - 16);
              wren = wren & 0xfff;
              stringstream ss;
              ss << setw(3) << setfill('0') << hex << wren;
              string idx = ss.str();
              string ram_wren = "0x01015" + idx;

              output_file << ram_wren << endl;

              output_file << enable << endl;
              output_file << "0x01010000" << endl;
              output_file << enable << endl;
            }
          if (!(i == asic_num - 1 && j == 130))
            {
              output_file << wait << endl;
            }
        }
    }
  output_file.close();

  cout << cYELLOW << "threshold txt sucess output " << filename << endl;
  cout << endl;
}

void unpack_process::threshold_to_gbt_same(vector<double> threshold)
{
  vector<double> th;

  th = threshold;

  double sum = 0.0;
  int count = 0;
  for (double value : th)
    {
      if (value * LSB < 15) // 15 fC
        {
          sum += value;
        }
      else
        {
          count++;
        }
    }
  double mean = sum / (th.size() - count);
  cout << "mean: " << mean * LSB << endl;

  long DataMSB = 0x0101;
  long DataLSB = 0x0102;
  string enable = "0x01020001";

  string wait = "&1";

  ostringstream datamsb;
  ostringstream datalsb;

  string bin_str;
  string bin_res;
  string bin_addr;
  string m_str;
  string l_str;
  string datamsb_str;
  string datalsb_str;

  string filename = file_write;
  ofstream output_file(filename, ios::out | ios::trunc);

  for (int j = 0; j < 131; j++)
    {

      for (int k = 0; k < 2; k++)
        {

          string wr_msb_en = "0x0101400" + to_string(k);

          output_file << wr_msb_en << endl;
          output_file << enable << endl;

          bitset<24> bits((int)(mean));
          bitset<8> bits3(j + 1);
          bin_str = bits.to_string();
          bin_addr = bits3.to_string();
          bin_res = bin_addr + bin_str;

          m_str = bin_res.substr(0, 16);
          l_str = bin_res.substr(16, 16);

          bitset<16> bits1(m_str);
          int msb = bits1.to_ulong();

          bitset<16> bits2(l_str);
          int lsb = bits2.to_ulong();

          datamsb << "0x" << setfill('0') << setw(4) << hex << DataMSB << setw(4) << hex << msb;
          datamsb_str = datamsb.str();

          datalsb << "0x" << setfill('0') << setw(4) << hex << DataMSB << setw(4) << hex << lsb;
          datalsb_str = datalsb.str();

          if (k == 0)
            {
              output_file << datamsb_str << endl;
            }
          else
            {
              output_file << datalsb_str << endl;
            }

          output_file << enable << endl;
          output_file << wait << endl;
          datamsb.str("");
          datalsb.str("");
        }
      output_file << "0x01014012" << endl;
      output_file << enable << endl;
      output_file << "0x01010000" << endl;
      output_file << enable << endl;
      output_file << wait << endl;

      // WREN EN
      if (asic_num <= 16)
        {
          output_file << "0x01015000" << endl;
          output_file << enable << endl;

          string ram_wren = "0x0101ffff";
          output_file << ram_wren << endl;

          output_file << enable << endl;
        }
      else
        {

          string ram_wren = "0x010150ff";
          output_file << ram_wren << endl;
          output_file << enable << endl;
          output_file << "0x0101ffff" << endl;
          output_file << enable << endl;
        }
      if (!(j == 130))
        {
          output_file << wait << endl;
        }
    }

  output_file.close();

  cout << cYELLOW << "threshold txt sucess output " << filename << endl;
  cout << endl;
}

void unpack_process::draw(vector<vector<double>> means, vector<vector<double>> rms)
{
  string filename = "base";
  gStyle->SetImageScaling(3.);
  TCanvas *c1 = new TCanvas(filename.c_str(), filename.c_str());
  // 将画布分割成1行2列
  c1->Divide(6, 4);

  for (int i = 0; i < asic_num; i++)
    {
      TGraph *gr = new TGraph(means[i].size());
      for (int j = 0; j < means[i].size(); j++)
        {
          gr->SetPoint(j, j, means[i][j]);
        }

      c1->cd(i + 1); // 切换到第一个子画布
      gPad->SetGrid();
      string title = "Chip" + to_string(i);
      gr->SetTitle(title.c_str());
      gr->SetMarkerColor(4);
      gr->SetMarkerStyle(21);
      gr->SetMarkerSize(0.5);
      gr->Draw("APL");
      gr->GetXaxis()->SetRangeUser(0, 127);
    }
  string save_filename = save_path + "base.png";
  c1->SaveAs(save_filename.c_str());

  // rms
  string filename1 = "rms";
  gStyle->SetImageScaling(3.);
  TCanvas *c2 = new TCanvas(filename1.c_str(), filename1.c_str());
  c2->Divide(6, 4);

  for (int i = 0; i < asic_num; i++)
    {
      TGraph *gr = new TGraph(rms[i].size());
      for (int j = 0; j < rms[i].size(); j++)
        {
          gr->SetPoint(j, j, rms[i][j]);
        }

      c2->cd(i + 1); // 切换到第一个子画布
      gPad->SetGrid();
      string title = "Chip" + to_string(i);
      gr->SetTitle(title.c_str());
      gr->SetMarkerColor(4);
      gr->SetMarkerStyle(21);
      gr->SetMarkerSize(0.5);
      gr->Draw("APL");
      gr->GetXaxis()->SetRangeUser(0, 127);
    }
  string save_filename1 = save_path + "rms.png";
  c2->SaveAs(save_filename1.c_str());
}

void unpack_process::write_base_txt(vector<vector<double>> means, vector<vector<double>> rms, vector<vector<double>> threshold)
{

  string filename = save_path + "base.txt";
  ofstream file(filename, ios::out | ios::trunc);

  for (int i = 0; i < means[0].size(); i++)
    {

      for (int j = 0; j < means.size(); j++)
        {
          file << means[j][i] << " ";
        }
      file << endl;
    }
  file.close();

  string filename1 = save_path + "rms.txt";
  ofstream file1(filename1, ios::out | ios::trunc);
  for (int i = 0; i < rms[0].size(); i++)
    {

      for (int j = 0; j < rms.size(); j++)
        {
          file1 << rms[j][i] << " ";
        }
      file1 << endl;
    }

  string filename2 = save_path + "thresh.txt";
  ofstream file2(filename2, ios::out | ios::trunc);
  for (int i = 0; i < threshold[0].size(); i++) {
    for (int j = 0; j < threshold.size(); j++) {
      file2 << threshold[j][i] << " ";
    }
    file2 << endl;
  }
}
